﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DeepZoomPivotConstructor.PivotLib;
using PaperRenderingInterfaces;
using HtmlAgilityPack;
using System.Text.RegularExpressions;

namespace PaperPluginUtilities
{
    /// <summary>
    /// Some helpers for common things having to do with pvi's (and their enumerations).
    /// </summary>
    public static class PivotImageHelpers
    {
        /// <summary>
        /// If the time returned by a date on image request is less than this number, then
        /// we assume that the web server is just playing with us and always returning the
        /// current time instead of actually doing something sensible.
        /// </summary>
        const double MinTimeDelayForValidDate = 10.0;

        /// <summary>
        /// Ask for the modification date. If it looks "off", then don't set the date! :-)
        /// </summary>
        /// <param name="pvi"></param>
        /// <param name="imageUrl"></param>
        public static void SetDateFromUrl(this PivotImage pvi, Uri imageUrl, IWebAccess WebGetter)
        {
            DateTime? whenModified = WebGetter.GetLastModificationTime(imageUrl);
            if (whenModified.HasValue)
            {
                TimeSpan tdiff = DateTime.Now - whenModified.Value;
                if (tdiff.TotalMinutes > MinTimeDelayForValidDate)
                {
                    pvi.Add("Date", whenModified.Value);
                }
            }
        }

        /// <summary>
        /// Use the URI to get a date/time if the returned image dosen't have one yet.
        /// </summary>
        /// <param name="images"></param>
        /// <param name="pageToUseAsDate"></param>
        /// <param name="WebGetter"></param>
        /// <returns></returns>
        public static IEnumerable<PivotImage> AddMissingDate(this IEnumerable<PivotImage> images, Uri pageToUseAsDate, IWebAccess WebGetter)
        {
            DateTime? pageTime = null;
            foreach (var item in images)
            {
                if (!item.Any(md => (md.Name == "Date" && (md as PivotMetadataDateTime) != null)))
                {
                    if (!pageTime.HasValue)
                    {
                        pageTime = WebGetter.GetLastModificationTime(pageToUseAsDate);
                        if (pageTime.HasValue && (DateTime.Now - pageTime.Value).TotalMinutes < MinTimeDelayForValidDate)
                        {
                            pageTime = null;
                        }
                        if (!pageTime.HasValue)
                        {
                            pageTime = ExtractFromTwiki(pageToUseAsDate, WebGetter);
                        }
                        if (!pageTime.HasValue)
                        {
                            pageTime = DateTime.Now;
                        }
                    }
                    item.Add("Date", pageTime.Value);
                }
                yield return item;
            }
        }

        /// <summary>
        /// Help us get the date/time out of the twiki page link info.
        /// </summary>
        static Regex DateFinder = null;

        /// <summary>
        /// Some special code to extract the revision date from a twiki page.
        /// </summary>
        /// <param name="pageToUseAsDate"></param>
        /// <param name="WebGetter"></param>
        /// <returns></returns>
        private static DateTime? ExtractFromTwiki(Uri pageToUseAsDate, IWebAccess WebGetter)
        {
            HtmlDocument doc = new HtmlDocument();
            doc.LoadHtml(WebGetter.GetUriAsString(pageToUseAsDate));

            var allLinks = new EnumerableWrapper<HtmlNode>(doc.DocumentNode.SelectNodes("//a [@title]"));

            var title = from l in allLinks
                        let t = l.Attributes["title"].Value
                        where t.StartsWith("Topic revision")
                        select t;
            string revisionInfo = title.FirstOrDefault();
            if (revisionInfo == null)
            {
                return null;
            }

            if (DateFinder == null)
            {
                DateFinder = new Regex("\\(([^')]+)\\)");
            }
            var m = DateFinder.Match(revisionInfo);
            if (!m.Success)
            {
                return null;
            }

            var splitTimes = m.Groups[1].Value.Split(new char[] { ' ', '-' }, StringSplitOptions.RemoveEmptyEntries);
            var day = splitTimes[0];
            var month = splitTimes[1];
            var year = splitTimes[2];
            var time = splitTimes[3];

            var dtString = month + " " + day + ", " + year + " " + time;

            try
            {
                DateTime result = Convert.ToDateTime(dtString);
                return result;
            }
            catch
            {
            }

            return null;

        }
    }
}
